//*****************************************************************************
// JFab (http://code.google.com/p/jfab)
// Copyright (c) 2011-2012 JFab.org
// Admin jfab@jeffreythompson.net
//
// See the file "LICENSE.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//*****************************************************************************

package org.jfab.core.adapter;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.jfab.core.model.CGType;

/**
 * Provides an adapter for <code>CGType</code>.
 */
public class CGTypeAdapter implements Adapter<CGType>
{
    @Override
    public String marshal(final CGType value)
    {
        String answer = null;

        if (value != null)
        {
            if (StringUtils.isNotEmpty(value.getPackageName()))
            {
                answer = value.getPackageName() + "." + value.getName();
            }
            else
            {
                answer = value.getName();
            }

            final String typeParametersString = createTypeParametersString(value);

            if (StringUtils.isNotEmpty(typeParametersString))
            {
                answer += typeParametersString;
            }
        }

        return answer;
    }

    @Override
    public CGType unmarshal(final String value)
    {
        CGType answer = null;

        if (StringUtils.isNotEmpty(value))
        {
            answer = new CGType();

            answer.setPackageName(parsePackageName(value));
            answer.setName(parseName(value));

            final List<CGType> typeParameters = parseTypeParameters(value);

            if (typeParameters != null)
            {
                answer.getTypeParameters().addAll(typeParameters);
            }
        }

        return answer;
    }

    /**
     * @param value Value.
     * 
     * @return a new type parameters string.
     */
    private String createTypeParametersString(final CGType value)
    {
        String answer = null;

        if (CollectionUtils.isNotEmpty(value.getTypeParameters()))
        {
            final StringBuilder sb = new StringBuilder();
            sb.append("<");
            final int size = value.getTypeParameters().size();
            for (int i = 0; i < size; i++)
            {
                final CGType typeParameter = value.getTypeParameters().get(i);
                sb.append(marshal(typeParameter));
                if (i < (size - 1))
                {
                    sb.append(", ");
                }
            }
            sb.append(">");
            answer = sb.toString();
        }

        return answer;
    }

    /**
     * @param value Value.
     * 
     * @return the type name.
     */
    private String parseName(final String value)
    {
        String answer;

        final String className = stripGenericTypes(value);

        final int index1 = className.lastIndexOf('.');

        if (index1 >= 0)
        {
            answer = className.substring(index1 + 1);
        }
        else
        {
            answer = className;
        }

        return answer;
    }

    /**
     * @param value Value.
     * 
     * @return the package name.
     */
    private String parsePackageName(final String value)
    {
        String answer = null;

        final String className = stripGenericTypes(value);

        final int index1 = className.lastIndexOf('.');

        if (index1 >= 0)
        {
            answer = className.substring(0, index1);
        }

        return answer;
    }

    /**
     * @param value Value.
     * 
     * @return the type parameters, or null if there aren't any.
     */
    private List<CGType> parseTypeParameters(final String value)
    {
        List<CGType> answer = null;

        final int index0 = value.indexOf("<");

        if (index0 >= 0)
        {
            final int index1 = value.lastIndexOf(">");

            if (index1 >= index0)
            {
                final String typeParams = value.substring(index0 + 1, index1);
                final String[] typeParameters = typeParams.split(",");

                if (ArrayUtils.isNotEmpty(typeParameters))
                {
                    answer = new ArrayList<CGType>();
                    for (final String typeParameter : typeParameters)
                    {
                        final CGType cgType = unmarshal(typeParameter.trim());
                        answer.add(cgType);
                    }
                }
            }
        }

        return answer;
    }

    /**
     * @param className Class name.
     * 
     * @return class name without generic types.
     */
    private String stripGenericTypes(final String className)
    {
        String answer = className;

        if (StringUtils.isNotEmpty(answer))
        {
            final int index = answer.indexOf('<');

            if (index >= 0)
            {
                answer = answer.substring(0, index);
            }
        }

        return answer;
    }
}
